/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
/* Copyright (C) 2012 Zongyou Yao. All rights reserved.     */

#ifndef LIST_INCLUDED
#define LIST_INCLUDED

/**
 * All list functions accept a null list_t for any list argument and interpret it
 * as the emtpy list.
 */
typedef struct list_t * list_t;

struct list_t {
    list_t rest;
    void *first;
};

/**
 * Appends tail to list and returns list. If list = null, list_append
 * returns tail.
 */
list_t list_append(list_t list, list_t tail);

/**
 * Creates and returns a top-level copy of list.
 * Exception mem_failed can be raised.
 */
list_t list_copy(list_t list);

/**
 * Creates and returns a list whose elements are the "..." arguments up to
 * the first null pointer.
 * Exception mem_failed can be raised.
 */
list_t list_list(void *x, ...);

/**
 * Assigns list->first to *x, if x is nonnull, deallocates list, and
 * returns list->rest. If list == null, list_pop returns null and does not
 * change *x.
 */
list_t list_pop(list_t list, void **x);

/**
 * Adds a new element that holds x onto the front of list and returns the
 * new list.
 * Exception mem_failed can be raised.
 */
list_t list_push(list_t list, void *x);

/**
 * Reverse the elements in list in place and returns the reversed list.
 */
list_t list_reverse(list_t list);

/**
 * Returns the number of elements in list.
 */
int list_length(list_t list);

/**
 * Deallocates and clears *list. It is a checked runtime error for list = null.
 */
void list_free(list_t *list);

/**
 * Calls apply(&p->first, cl) for each element p in list. It is an unchecked runtime
 * error for apply to change list.
 */
void list_map(list_t list, void apply(void **x, void *cl), void *cl);

/**
 * Creates an N + 1 element array of the N elements in list and returns a pointer
 * to its first element. The Nth element in the array is end.
 * Exception mem_failed can be raised.
 */
void **list_toarray(list_t list, void *end);

#endif
